#define CROW_MAIN // 在包含 crow.h 之前定义此宏，以便生成 main() 函数
#include "crow.h" // 如果你下载的是 crow_all.h，就用那个文件名
#include "nlohmann/json.hpp"

// 标准 C++ 头文件
#include <string>       // 字符串处理
#include <vector>       // 向量 (虽然这里主要用 json 数组)
#include <mutex>        // 互斥锁，用于线程同步
#include <atomic>       // 原子操作，用于线程安全的 ID 生成
#include <chrono>       // 时间处理
#include <iomanip>      // I/O 格式化 (例如 put_time)
#include <sstream>      // 字符串流
#include <iostream>     // 用于输出日志/错误信息
#include <memory>       // 用于智能指针 (管理 FILE*)
#include <algorithm>    // 用于 std::find_if, std::max

// C 标准头文件 (用于二进制文件 I/O)
#include <cstdio>       // 包含 C 标准 I/O 头文件 (fopen, fread, fwrite, fclose 等)

// 使用 nlohmann::json 简化 JSON 操作
using json = nlohmann::json;

// --- 配置 ---
const std::string TASKS_FILE = "tasks.json"; // 任务数据文件名

// --- 全局状态与同步 ---
// 使用一个简单的互斥锁来保护文件访问和内存中的数据
std::mutex tasks_mutex;
// 使用原子整数来确保线程安全地生成下一个任务 ID
std::atomic<int> next_task_id = 1; // ID 从 1 开始

// --- 辅助函数 ---

// 获取当前时间的 ISO 8601 格式字符串 (UTC)
std::string getCurrentTimestampISO8601() {
    auto now = std::chrono::system_clock::now();
    auto itt = std::chrono::system_clock::to_time_t(now);
    std::ostringstream ss;
    // 使用 std::gmtime 获取 UTC 时间
    ss << std::put_time(std::gmtime(&itt), "%Y-%m-%dT%H:%M:%SZ");
    return ss.str();
}

// 从 JSON 文件加载任务列表 (使用二进制 I/O，支持 UTF-8)
json loadTasks() {
    json tasks_data = json::array(); // 默认为空数组

    // 使用 C 风格 fopen 以二进制读取模式 ("rb") 打开文件
    // 使用 std::unique_ptr 自动管理 FILE* 资源 (RAII)，确保文件总是被关闭
    std::unique_ptr<FILE, decltype(&fclose)> file_ptr(
        fopen(TASKS_FILE.c_str(), "rb"), // "rb" = read binary (二进制读)
        fclose
    );
    FILE* file = file_ptr.get(); // 获取原始指针

    if (file) { // 文件成功打开
        // 将文件指针移动到末尾以获取文件大小
        fseek(file, 0, SEEK_END);
        long file_size = ftell(file); // 获取文件大小（字节数）
        // 将文件指针移回文件开头
        rewind(file);

        if (file_size > 0) { // 文件有内容
            // 创建一个字符串缓冲区来存储文件内容
            std::string buffer(file_size, '\0'); // 分配足够空间

            // 将整个文件读入缓冲区
            size_t bytes_read = fread(&buffer[0], 1, file_size, file);

            if (bytes_read == static_cast<size_t>(file_size)) { // 确保读取了所有字节
                try {
                    // 解析从文件读取的 UTF-8 字节流
                    // nlohmann::json::parse 可以处理 UTF-8 字符串
                    tasks_data = json::parse(buffer);
                    // 确保解析结果是 JSON 数组
                    if (!tasks_data.is_array()) {
                        std::cerr << "警告: " << TASKS_FILE << " 内容解析后不是有效的 JSON 数组，将使用空数组。" << std::endl;
                        tasks_data = json::array();
                    }
                } catch (json::parse_error& e) {
                    std::cerr << "错误: 解析 " << TASKS_FILE << " 失败: " << e.what() << std::endl;
                    tasks_data = json::array(); // 解析出错时返回空数组
                }
            } else { // 读取字节数与文件大小不符
                std::cerr << "错误: 读取 " << TASKS_FILE << " 时发生错误 (预期读取 " << file_size << " 字节, 实际读取 " << bytes_read << " 字节)。" << std::endl;
                tasks_data = json::array();
            }
        } else if (file_size == 0) {
             // 文件为空，返回空数组是正确的
             tasks_data = json::array();
        } else { // 获取文件大小出错 (ftell 可能返回 -1L)
            std::cerr << "错误: 无法确定 " << TASKS_FILE << " 的文件大小。" << std::endl;
            tasks_data = json::array();
        }
        // 文件关闭由 unique_ptr 在其析构时自动处理 (调用 fclose)
    } else { // 文件打开失败
        // 文件不存在或无法打开，假定任务列表为空 (首次运行时正常)
        // std::cout << "信息: " << TASKS_FILE << " 未找到或无法打开。将视为空任务列表。" << std::endl;
        tasks_data = json::array();
    }

    return tasks_data;
}

// 将任务列表保存到 JSON 文件 (使用二进制 I/O，支持 UTF-8)
bool saveTasks(const json& tasks_data) {
    // 确保我们正在保存的是一个 JSON 数组
    if (!tasks_data.is_array()) {
         std::cerr << "错误: 尝试将非数组类型的 JSON 数据保存到 " << TASKS_FILE << std::endl;
         return false;
    }

    try {
        // 将 JSON 对象序列化为带缩进的 UTF-8 字符串
        // dump() 默认生成 UTF-8 编码
        std::string buffer = tasks_data.dump(2); // 2 个空格缩进

        // 使用 C 风格 fopen 以二进制写入模式 ("wb") 打开文件
        // "wb" 会清空已存在的文件内容，或创建新文件。
        std::unique_ptr<FILE, decltype(&fclose)> file_ptr(
            fopen(TASKS_FILE.c_str(), "wb"), // "wb" = write binary (二进制写)
            fclose
        );
        FILE* file = file_ptr.get();

        if (file) { // 文件成功打开
            // 将序列化后的字符串内容写入文件
            size_t bytes_written = fwrite(buffer.c_str(), 1, buffer.length(), file);

            if (bytes_written == buffer.length()) { // 确保所有字节都已写入
                // 写入成功
                // 文件关闭由 unique_ptr 自动处理
                return true;
            } else { // 写入字节数与预期不符
                std::cerr << "错误: 写入 " << TASKS_FILE << " 时发生错误 (预期写入 " << buffer.length() << " 字节, 实际写入 " << bytes_written << " 字节)。" << std::endl;
                // 文件关闭仍由 unique_ptr 自动处理
                return false;
            }
        } else { // 文件打开失败
            std::cerr << "错误: 无法打开 " << TASKS_FILE << " 进行写入。" << std::endl;
            return false;
        }
    } catch (const std::exception& e) {
        // 捕获 json::dump() 可能抛出的异常 (虽然不常见)
        std::cerr << "错误: JSON 序列化过程中发生异常: " << e.what() << std::endl;
        return false;
    }
}

// 根据现有任务初始化 next_task_id
void initializeNextId(const json& tasks_data) {
    int max_id = 0;
    if (tasks_data.is_array()) {
        for (const auto& task : tasks_data) {
            // 检查任务是否有 id 字段且是整数
            if (task.contains("id") && task["id"].is_number_integer()) {
                max_id = std::max(max_id, task["id"].get<int>());
            }
        }
    }
    // 将下一个 ID 设置为当前最大 ID + 1
    next_task_id = max_id + 1;
    std::cout << "信息: 初始化下一个任务 ID 为: " << next_task_id << std::endl;
}


// --- 主应用程序 ---
int main() {
    crow::SimpleApp app; // 创建 Crow 应用实例

    // --- 初始加载和 ID 初始化 ---
    { // 使用代码块限制锁的作用域
        std::lock_guard<std::mutex> lock(tasks_mutex); // 加锁以安全地进行初始加载
        json initial_tasks = loadTasks(); // 使用支持 UTF-8 的加载函数
        initializeNextId(initial_tasks);
        // 可选：如果 loadTasks 创建或修正了文件（例如，将空文件或无效文件变为空数组[]），
        // 可以立即保存一次以确保文件内容正确。
        // saveTasks(initial_tasks);
    } // 锁在此处自动释放


    // --- API 路由定义 ---

    // GET /api/v1/tasks - 列出所有任务
    CROW_ROUTE(app, "/api/v1/tasks").methods(crow::HTTPMethod::Get)
    ([]() {
        std::lock_guard<std::mutex> lock(tasks_mutex); // 读取时加锁
        json tasks = loadTasks();
        crow::response res(tasks.dump()); // dump() 生成 UTF-8 JSON 字符串
        // 明确设置响应头 Content-Type，包含 charset=utf-8
        res.add_header("Content-Type", "application/json; charset=utf-8");
        return res;
    });

    // POST /api/v1/tasks - 创建一个新任务
    CROW_ROUTE(app, "/api/v1/tasks").methods(crow::HTTPMethod::Post)
    ([](const crow::request& req) {
        json task_input;
        try {
            // Crow 的 req.body 应该能正确处理来自请求的 UTF-8 数据
            task_input = json::parse(req.body);
        } catch (json::parse_error& e) {
            // 返回中文错误信息
            return crow::response(400, json{{"error", "无效的 JSON 格式: " + std::string(e.what())}}.dump());
        }

        // 验证必需字段 'title'
        if (!task_input.contains("title") || !task_input["title"].is_string() || task_input["title"].get<std::string>().empty()) {
            return crow::response(400, json{{"error", "缺少或无效的 'title' 字段 (必须是非空字符串)"}}.dump());
        }

        // 验证可选字段 'status' (如果存在)
        if (task_input.contains("status")) {
            if (!task_input["status"].is_string()) {
                 return crow::response(400, json{{"error", "无效的 'status' 字段类型 (必须是字符串)"}}.dump());
            }
            std::string status = task_input["status"];
             if (status != "todo" && status != "in_progress" && status != "done") {
                 return crow::response(400, json{{"error", "无效的 'status' 值。必须是 'todo', 'in_progress', 或 'done' 之一。"}}.dump());
            }
        }
        // 验证可选字段 'due_date' (如果存在)
        if (task_input.contains("due_date") && !task_input["due_date"].is_string() && !task_input["due_date"].is_null()) {
             return crow::response(400, json{{"error", "无效的 'due_date' 字段类型 (必须是 ISO 8601 格式的字符串或 null)"}}.dump());
        }

        std::lock_guard<std::mutex> lock(tasks_mutex); // 修改数据前加锁
        json tasks = loadTasks(); // 重新加载以获取最新数据

        json new_task;
        new_task["id"] = next_task_id++; // 分配下一个 ID 并原子地递增
        new_task["title"] = task_input["title"]; // nlohmann::json 本身支持 UTF-8 字符串
        new_task["description"] = task_input.value("description", ""); // 获取 description，如果不存在则为空字符串
        new_task["status"] = task_input.value("status", "todo");       // 获取 status，如果不存在则默认为 "todo"
        if (task_input.contains("due_date") && task_input["due_date"].is_string()) {
             new_task["due_date"] = task_input["due_date"];
        } else {
             new_task["due_date"] = nullptr; // 对于可选字段，使用 JSON null
        }
        std::string now = getCurrentTimestampISO8601();
        new_task["created_at"] = now;
        new_task["updated_at"] = now;

        tasks.push_back(new_task); // 将新任务添加到数组

        if (saveTasks(tasks)) { // 使用支持 UTF-8 的保存函数
            // 返回 201 Created 状态码和新创建的任务数据
            crow::response res(201, new_task.dump());
            res.add_header("Content-Type", "application/json; charset=utf-8");
            // 可选：添加 Location 头指向新资源
            // res.add_header("Location", "/api/v1/tasks/" + std::to_string(new_task["id"].get<int>()));
            return res;
        } else {
            // 如果保存失败，尝试回滚 ID（简单方法）
            next_task_id--;
            return crow::response(500, json{{"error", "无法将新任务保存到文件"}}.dump());
        }
    });

    // GET /api/v1/tasks/{taskId} - 获取指定 ID 的任务
    CROW_ROUTE(app, "/api/v1/tasks/<int>") // <int> 捕获路径参数作为整数
        .methods(crow::HTTPMethod::Get)
    ([](int taskId) { // taskId 参数会自动从 URL 中提取
        if (taskId <= 0) { // 基本的 ID 验证
             return crow::response(400, json{{"error", "无效的任务 ID"}}.dump());
        }

        std::lock_guard<std::mutex> lock(tasks_mutex); // 读取时加锁
        json tasks = loadTasks();
        // 使用 std::find_if 查找具有匹配 ID 的任务
        auto it = std::find_if(tasks.begin(), tasks.end(),
                               [taskId](const json& task) {
                                   // 确保任务对象包含 "id" 字段且值等于 taskId
                                   return task.contains("id") && task["id"].is_number_integer() && task["id"] == taskId;
                               });

        if (it != tasks.end()) { // 找到了任务
            crow::response res(it->dump());
            res.add_header("Content-Type", "application/json; charset=utf-8");
            return res;
        } else { // 未找到任务
            return crow::response(404, json{{"error", "任务未找到"}}.dump());
        }
    });

    // PUT /api/v1/tasks/{taskId} - 更新现有任务
    CROW_ROUTE(app, "/api/v1/tasks/<int>")
        .methods(crow::HTTPMethod::Put)
    ([](const crow::request& req, int taskId) {
         if (taskId <= 0) {
             return crow::response(400, json{{"error", "无效的任务 ID"}}.dump());
        }

        json task_update;
        try {
            task_update = json::parse(req.body);
        } catch (json::parse_error& e) {
            return crow::response(400, json{{"error", "无效的 JSON 格式: " + std::string(e.what())}}.dump());
        }

        // 验证 PUT 请求的必需字段 (根据 TaskInput schema)
        if (!task_update.contains("title") || !task_update["title"].is_string() || task_update["title"].get<std::string>().empty()) {
            return crow::response(400, json{{"error", "缺少或无效的 'title' 字段 (必须是非空字符串)"}}.dump());
        }
        // 验证 status (如果提供)
        if (task_update.contains("status")) {
            if (!task_update["status"].is_string()) {
                 return crow::response(400, json{{"error", "无效的 'status' 字段类型 (必须是字符串)"}}.dump());
            }
             std::string status = task_update["status"];
             if (status != "todo" && status != "in_progress" && status != "done") {
                 return crow::response(400, json{{"error", "无效的 'status' 值。必须是 'todo', 'in_progress', 或 'done' 之一。"}}.dump());
            }
        }
        // 验证 due_date (如果提供)
        if (task_update.contains("due_date") && !task_update["due_date"].is_string() && !task_update["due_date"].is_null()) {
             return crow::response(400, json{{"error", "无效的 'due_date' 字段类型 (必须是 ISO 8601 格式的字符串或 null)"}}.dump());
        }

        std::lock_guard<std::mutex> lock(tasks_mutex); // 修改数据前加锁
        json tasks = loadTasks();
        auto it = std::find_if(tasks.begin(), tasks.end(),
                               [taskId](const json& task) {
                                   return task.contains("id") && task["id"].is_number_integer() && task["id"] == taskId;
                               });

        if (it != tasks.end()) { // 找到了要更新的任务
            json& task_to_update = *it; // 获取任务对象的引用

            // 使用请求体中的数据更新任务字段 (PUT 通常替换所有可编辑字段)
            task_to_update["title"] = task_update["title"];
            // 如果请求中没提供，则使用默认值（空字符串或 "todo"）
            task_to_update["description"] = task_update.value("description", "");
            task_to_update["status"] = task_update.value("status", "todo");
            // 处理 due_date，允许设置为 null 或新字符串
            if (task_update.contains("due_date")) {
                 if (task_update["due_date"].is_null()) {
                     task_to_update["due_date"] = nullptr; // 设置为 null
                 } else { // 之前已验证为字符串
                     task_to_update["due_date"] = task_update["due_date"]; // 更新为新日期字符串
                 }
            } else {
                 // 如果 PUT 请求中没有 due_date，根据 RESTful 风格，通常应将其移除或设为默认值 (这里用 null)
                 task_to_update["due_date"] = nullptr;
            }

            task_to_update["updated_at"] = getCurrentTimestampISO8601(); // 更新修改时间戳

            if (saveTasks(tasks)) { // 保存更改
                crow::response res(task_to_update.dump());
                res.add_header("Content-Type", "application/json; charset=utf-8");
                return res;
            } else { // 保存失败
                return crow::response(500, json{{"error", "无法保存更新后的任务"}}.dump());
            }
        } else { // 未找到任务
            return crow::response(404, json{{"error", "任务未找到，无法更新"}}.dump());
        }
    });

    // DELETE /api/v1/tasks/{taskId} - 删除一个任务
    CROW_ROUTE(app, "/api/v1/tasks/<int>")
        .methods(crow::HTTPMethod::Delete)
    ([](int taskId) {
         if (taskId <= 0) {
             return crow::response(400, json{{"error", "无效的任务 ID"}}.dump());
        }

        std::lock_guard<std::mutex> lock(tasks_mutex); // 修改数据前加锁
        json tasks = loadTasks();
        // 查找具有匹配 ID 的任务
        auto it = std::find_if(tasks.begin(), tasks.end(),
                               [taskId](const json& task) {
                                   return task.contains("id") && task["id"].is_number_integer() && task["id"] == taskId;
                               });

        if (it != tasks.end()) { // 找到了任务
            tasks.erase(it); // 从 JSON 数组中删除

            if (saveTasks(tasks)) { // 保存更改
                // 删除成功，返回 204 No Content (表示成功但无响应体)
                return crow::response(204);
            } else { // 保存失败
                // 注意：此时任务可能已从内存中删除，但文件未更新，状态可能不一致
                return crow::response(500, json{{"error", "删除任务后无法保存更改"}}.dump());
            }
        } else { // 未找到任务
            return crow::response(404, json{{"error", "任务未找到，无法删除"}}.dump());
        }
    });

    // --- 运行服务器 ---
    // 尝试设置控制台输出为 UTF-8 (仅 Windows 特定，可能不适用于所有终端)
    // 这有助于在调试时通过 cout/cerr 打印 UTF-8 字符时不出现乱码。
    #ifdef _WIN32
        // "> nul" 用于抑制 chcp 命令本身的输出
        system("chcp 65001 > nul"); // 将控制台代码页设置为 UTF-8
        std::cout << "信息: (Windows) 尝试将控制台代码页设置为 UTF-8 (65001)。" << std::endl;
    #endif

    app.port(8080)        // 设置端口号，与 OpenAPI 规范一致
       .multithreaded()   // 启用多线程处理并发请求
       .run();           // 启动服务器并开始监听

    // 如果 run() 成功，程序将在此处阻塞，直到服务器停止
    // run() 之后的代码通常不会执行，除非服务器正常停止
    return 0;
}
